#include "Stat.h"
#include <stdio.h>
#include <string.h>
#include "statSelect.h"

namespace ment {

    Stat::Stat(StatType type)
	: type(type),
	stat(nullptr),
	stat2(nullptr),
	statList(nullptr),
	select(nullptr),
	name(nullptr),
	table(nullptr),
	alias(nullptr),
	fval(0),
	ival(0),
	ival2(0),
	datetimeField(kDatetimeNone),
	isBoolLiteral(false),
	opType(kOpNone),
	distinct(false) {};

    Stat::~Stat() {
	delete stat;
	delete stat2;
	delete select;
	delete[] name;
	free(table);
	free(alias);

	if (statList != nullptr) {
	    for (Stat* e : *statList) {
		delete e;
	    }
	    delete statList;
	}
    }

    Stat* Stat::make(StatType type) {
	Stat* e = new Stat(type);
	return e;
    }

    Stat* Stat::makeOpUnary(OperatorType op, Stat* stat) {
	Stat* e = new Stat(kStatOperator);
	e->opType = op;
	e->stat = stat;
	e->stat2 = nullptr;
	return e;
    }

    Stat* Stat::makeOpBinary(Stat* stat1, OperatorType op, Stat* stat2) {
	Stat* e = new Stat(kStatOperator);
	e->opType = op;
	e->stat = stat1;
	e->stat2 = stat2;
	return e;
    }

    Stat* Stat::makeBetween(Stat* stat, Stat* left, Stat* right) {
	Stat* e = new Stat(kStatOperator);
	e->stat = stat;
	e->opType = kOpBetween;
	e->statList = new std::vector<Stat*>();
	e->statList->push_back(left);
	e->statList->push_back(right);
	return e;
    }

    Stat* Stat::makeCaseList(Stat* caseListElement) {
	Stat* e = new Stat(kStatOperator);
	// Case list statessions are temporary and will be integrated into the case
	// statessions statList - thus assign operator type kOpNone
	e->opType = kOpNone;
	e->statList = new std::vector<Stat*>();
	e->statList->push_back(caseListElement);
	return e;
    }

    Stat* Stat::makeCaseListElement(Stat* when, Stat* then) {
	Stat* e = new Stat(kStatOperator);
	e->opType = kOpCaseListElement;
	e->stat = when;
	e->stat2 = then;
	return e;
    }

    Stat* Stat::caseListAppend(Stat* caseList, Stat* caseListElement) {
	caseList->statList->push_back(caseListElement);
	return caseList;
    }

    Stat* Stat::makeCase(Stat* stat, Stat* caseList, Stat* elseStat) {
	Stat* e = new Stat(kStatOperator);
	e->opType = kOpCase;
	e->stat = stat;
	e->stat2 = elseStat;
	e->statList = caseList->statList;
	caseList->statList = nullptr;
	delete caseList;
	return e;
    }

    Stat* Stat::makeLiteral(int64_t val) {
	Stat* e = new Stat(kStatLiteralInt);
	e->ival = val;
	return e;
    }

    Stat* Stat::makeLiteral(double value) {
	Stat* e = new Stat(kStatLiteralFloat);
	e->fval = value;
	return e;
    }

    Stat* Stat::makeLiteral(char* string) {
	Stat* e = new Stat(kStatLiteralString);
	e->name = new char[strlen(string) + 1];
	strcpy(e->name, string);
	return e;
    }
    Stat* Stat::makeLiteral(const char* string) {
	Stat* e = new Stat(kStatLiteralString);
	e->name = new char[strlen(string) + 1];
	strcpy(e->name, string);
	return e;
    }

    Stat* Stat::makeLiteral(bool val) {
	Stat* e = new Stat(kStatLiteralBool);
	e->ival = (int)val;
	e->isBoolLiteral = true;
	return e;
    }

    Stat* Stat::makeNullLiteral() {
	Stat* e = new Stat(kStatLiteralNull);
	return e;
    }

    Stat* Stat::makeColumnRef(char* name) {
	Stat* e = new Stat(kStatColumnRef);
	e->name = name;
	return e;
    }

    Stat* Stat::makeColumnRef(char* table, char* name) {
	Stat* e = new Stat(kStatColumnRef);
	e->name = name;
	e->table = table;
	return e;
    }

    Stat* Stat::makeStar(void) {
	Stat* e = new Stat(kStatStar);
	return e;
    }

    Stat* Stat::makeStar(char* table) {
	Stat* e = new Stat(kStatStar);
	e->table = table;
	return e;
    }

    Stat* Stat::makeFunctionRef(char* func_name, std::vector<Stat*>* statList,
	bool distinct) {
	Stat* e = new Stat(kStatFunctionRef);
	e->name = func_name;
	e->statList = statList;
	e->distinct = distinct;
	return e;
    }

    Stat* Stat::makeArray(std::vector<Stat*>* statList) {
	Stat* e = new Stat(kStatArray);
	e->statList = statList;
	return e;
    }

    Stat* Stat::makeArrayIndex(Stat* stat, int64_t index) {
	Stat* e = new Stat(kStatArrayIndex);
	e->stat = stat;
	e->ival = index;
	return e;
    }

    Stat* Stat::makeParameter(int id) {
	Stat* e = new Stat(kStatParameter);
	e->ival = id;
	return e;
    }

    Stat* Stat::makeSelect(SelectStatement* select) {
	Stat* e = new Stat(kStatSelect);
	e->select = select;
	return e;
    }

    Stat* Stat::makeExists(SelectStatement* select) {
	Stat* e = new Stat(kStatOperator);
	e->opType = kOpExists;
	e->select = select;
	return e;
    }

    Stat* Stat::makeInOperator(Stat* stat, std::vector<Stat*>* statList) {
	Stat* e = new Stat(kStatOperator);
	e->opType = kOpIn;
	e->stat = stat;
	e->statList = statList;

	return e;
    }

    Stat* Stat::makeInOperator(Stat* stat, SelectStatement* select) {
	Stat* e = new Stat(kStatOperator);
	e->opType = kOpIn;
	e->stat = stat;
	e->select = select;

	return e;
    }

    Stat* Stat::makeExtract(DatetimeField datetimeField, Stat* stat) {
	Stat* e = new Stat(kStatFunctionRef);
	e->name = _strdup("EXTRACT");
	e->datetimeField = datetimeField;
	e->stat = stat;
	return e;
    }

    bool Stat::isType(StatType statType) const { return statType == type; }

    bool Stat::isLiteral() const {
	return isType(kStatLiteralInt) || isType(kStatLiteralFloat) ||
	    isType(kStatLiteralString) || isType(kStatParameter) ||
	    isType(kStatLiteralNull);
    }

    bool Stat::hasAlias() const { return alias != nullptr; }

    bool Stat::hasTable() const { return table != nullptr; }

    const char* Stat::getName() const {
	if (alias != nullptr)
	    return alias;
	else
	    return name;
    }

    char* substr(const char* source, int from, int to) {
	int len = to - from;
	char* copy = (char*)malloc(len + 1);
	;
	strncpy(copy, source + from, len);
	copy[len] = '\0';
	return copy;
    }
    bool Stat::compare(Stat* val1, Stat* val2, OperatorType op)
    {
	if (val1->type != val2->type) {
	    if ((val1->type == kStatLiteralInt || val1->type == kStatLiteralFloat) && (val2->type == kStatLiteralInt || val2->type == kStatLiteralFloat)) {
		double ex1 = val1->type == kStatLiteralInt ? val1->ival : val1->fval;
		double ex2 = val2->type == kStatLiteralInt ? val2->ival : val2->fval;
		if (op == kOpEquals) {
		    return fabs(ex1 - ex2) < 1e-3;
		}
		else if (op == kOpGreater) {
		    return ex1 > ex2;
		}
		else if (op == kOpGreaterEq) {
		    return ex1 >= ex2;
		}
		else if (op == kOpLess) {
		    return ex1 < ex2;
		}
		else if (op == kOpLessEq) {
		    return ex1 <= ex2;
		}
	    }
	    else {
		return false;
	    }
	}
	else {
	    if (val1->type == kStatLiteralInt) {
		if (op == kOpEquals) {
		    return val1->ival == val2->ival;
		}
		else if (op == kOpGreater) {
		    return val1->ival > val2->ival;
		}
		else if (op == kOpGreaterEq) {
		    return val1->ival >= val2->ival;
		}
		else if (op == kOpLess) {
		    return val1->ival < val2->ival;
		}
		else if (op == kOpLessEq) {
		    return val1->ival <= val2->ival;
		}
	    }
	    else if (val1->type == kStatLiteralFloat) {
		if (op == kOpEquals) {
		    return val1->fval == val2->fval;
		}
		else if (op == kOpGreater) {
		    return val1->fval > val2->fval;
		}
		else if (op == kOpGreaterEq) {
		    return val1->fval >= val2->fval;
		}
		else if (op == kOpLess) {
		    return val1->fval < val2->fval;
		}
		else if (op == kOpLessEq) {
		    return val1->fval <= val2->fval;
		}
	    }
	    else if (val1->type == kStatLiteralNull) {
		if (op == kOpEquals || op == kOpGreaterEq || op == kOpLessEq) {
		    return true;
		}
		else
		    return false;
	    }
	    else if (val1->type == kStatLiteralString) {
		if (op == kOpEquals)
		    return strcmp(val1->name, val2->name) == 0;
		else
		    return false;
	    }
	}

	//9.15.7
	// 布尔类型值的逻辑
	if (val1->type == kStatLiteralBool) {
		bool b1 = val1->ival != 0;
		bool b2 = val2->ival != 0;
		switch (op) {
		case kOpEquals:    return b1 == b2;
		case kOpNotEquals: return b1 != b2;
		default:           return false;   // 布尔没有 > < 操作
		}
		}
	return false;
    }
}  // namespace hsql
